package com.taoyuanx.boot.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.Signature;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Enumeration;

import javax.crypto.Cipher;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.taoyuanx.boot.constant.ApiConstant;


public class RSAUtil {
	 private static final Logger log = LoggerFactory.getLogger(RSAUtil.class);
    public static final String CERT_TYPE_P12 = "PKCS12";
    public static final String ENCRYPT_TYPE_RSA = "RSA";
    public static final String DEFAILT_ALGORITHM = "MD5withRSA";
    public static final String CERT_DEFAULTPATH = "";
    public static final String CERT_TYPE_X509 = "X.509";
    public static KeyStore keyStore;
    public static String keyPassword = "";
	 static{
	  	  	try {	
				keyPassword =  PropertiesUtil.getSystemProperty(ApiConstant.SYSTEM_P12_PWD);
				String  filepPath=PropertiesUtil.getSystemProperty(ApiConstant.SYSTEM_P12_PATH);
				keyStore = getKeyStore(filepPath,keyPassword);
	  	  	}catch (Exception e) {
	  	  		log.error("加载配置错误{}",e);
			}
	    }
	 
	 
	 public static  KeyStore getKeyStore(String filePath, String keyPassword) throws Exception {
			KeyStore keyStore = KeyStore.getInstance(CERT_TYPE_P12);
			FileInputStream file = new FileInputStream(new File(filePath));
		    keyStore.load(file, keyPassword.toCharArray());
			return keyStore;
	    }
	    


	 /**
	  * 从 keystore 中获取公钥
	 * @param keyStore
	 * @return
	 * @throws Exception
	 */
	public static RSAPublicKey getPublicKey(KeyStore keyStore) throws Exception {
		 if(null==keyStore)keyStore=RSAUtil.keyStore;
		String key_aliases = null;
    	Enumeration<String> enumeration = keyStore.aliases();
    	key_aliases = enumeration.nextElement();
    	if (keyStore.isKeyEntry(key_aliases)) {
    		RSAPublicKey publicKey = (RSAPublicKey) keyStore.getCertificate(key_aliases).getPublicKey();
    		return publicKey;
    	}
		return null;
	}
	 


	/**从keystore 中获取私钥
	 * @param keyStore
	 * @param keyPassword
	 * @return
	 * @throws Exception
	 */
	public static RSAPrivateKey getPrivateKey(KeyStore keyStore,String keyPassword) throws Exception {
		 if(null==keyStore){
			 keyStore=RSAUtil.keyStore;
			 keyPassword=RSAUtil.keyPassword;
		 }
		String key_aliases = null;
		Enumeration<String> enumeration = keyStore.aliases();
		key_aliases = enumeration.nextElement();
		if (keyStore.isKeyEntry(key_aliases)) {
			RSAPrivateKey privateKey = (RSAPrivateKey) keyStore.getKey(key_aliases, keyPassword.toCharArray());
			return privateKey;
		}
		return null;
	}

	/**
	 * 公钥加密
	 * 
	 * @param data
	 * @param publicKey
	 * @return
	 * @throws Exception
	 */
	public static String encryptByPublicKey(String data,RSAPublicKey publicKey)
			throws Exception {
		if(null==publicKey){//如果公钥为空，采用系统公钥
			publicKey=getPublicKey(null);
		}
		Cipher cipher = Cipher.getInstance(ENCRYPT_TYPE_RSA);
		cipher.init(Cipher.ENCRYPT_MODE, publicKey);
		// 模长
		int key_len = publicKey.getModulus().bitLength() / 8;
		// 加密数据长度 <= 模长-11,如果明文长度大于模长-11则要分组加密
		key_len-=11;
		byte[] datas = data.getBytes();  
		byte[] dataReturn = null;
		for (int i = 0; i < datas.length; i += key_len) {
			byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(datas, i, i +key_len));
			dataReturn = ArrayUtils.addAll(dataReturn, doFinal);
		}
		return Base64.encodeBase64String(dataReturn);
	}
	
	
	

	/**
	 * 私钥解密
	 * 
	 * @param data
	 * @param privateKey
	 * @return
	 * @throws Exception
	 */
	public static String decryptByPrivateKey(String data,RSAPrivateKey privateKey)
			throws Exception {
		if(null == privateKey){//如果私钥为空采用系统私钥
			privateKey=getPrivateKey(null,null);
		}
		Cipher cipher = Cipher.getInstance(ENCRYPT_TYPE_RSA);
		cipher.init(Cipher.DECRYPT_MODE, privateKey);
		//模长
		int key_len = privateKey.getModulus().bitLength() / 8;
		//base64解密
		byte[] bytes = Base64.decodeBase64(data);
		//分组解密
		StringBuilder sb=new StringBuilder();
		// 如果密文长度大于模长则要分组解密
		for (int i = 0; i <bytes.length ; i += key_len) {
			byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(bytes, i, i + key_len));
			sb.append(new String(doFinal));
		}
		return sb.toString();
}
	
	   public static X509Certificate getPublicKeyCer(InputStream publicInput) throws Exception {
	    	CertificateFactory certificatefactory=CertificateFactory.getInstance(CERT_TYPE_X509);
			 X509Certificate cert = (X509Certificate)certificatefactory.generateCertificate(publicInput);
	    	return cert;
	    }
	   
	    /**签名
	     * @param data 签名内容
	     * @param algorithm 签名
	     * @param privateKey 签名私钥
	     * @return
	     * @throws Exception
	     */
	    public static String signData(byte[] data,String algorithm,RSAPrivateKey privateKey) throws Exception{
	    	if(null == privateKey){//如果私钥为空采用系统私钥
				privateKey=getPrivateKey(null,null);
			}
			if(null ==algorithm || algorithm.length()==0){
				algorithm = DEFAILT_ALGORITHM;
			}
			Signature signture = Signature.getInstance(algorithm);
			signture.initSign(privateKey);
			signture.update(data);
			return Base64.encodeBase64String(signture.sign());
		}
	    
	    /**
	     * @param content 签名原文内容
	     * @param signvalue 签名值
	     * @param cert 验签证书
	     * @return
	     */
	    public static boolean vefySign(String content,String signvalue,X509Certificate cert){
	    	try {
	    		if(null == signvalue|| null ==content)return false;
	    		Signature signature =null;
	    		if(null ==cert){
	    			signature= Signature.getInstance(DEFAILT_ALGORITHM);
					signature.initVerify(getPublicKey(null));
	    		}else{
	    			signature= Signature.getInstance(cert.getSigAlgName());
					signature.initVerify(cert.getPublicKey());
	    		}
				signature.update(content.getBytes());
				boolean bverify = signature.verify(Base64.decodeBase64(signvalue));
				return bverify;
			} catch (Exception e) {
				log.error("验签异常{}",e);
				return false;
			}
	    }
	   public static void main(String[] args) throws Exception {
		/*   String signData = RSAUtil.signData("123456".getBytes(), null,null);
		   System.out.println(RSAUtil.vefySign("123456", signData, null));*/
		   String str="123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123123";
		   String encryptByPublicKey = RSAUtil.encryptByPublicKey(str, null);
		   System.out.println("原文长度"+str.length()+":"+str);
		   String s=decryptByPrivateKey(encryptByPublicKey, null);
		   System.out.println("解密后长度:"+s.length()+":"+s);
		/*   KeyStore keyStore2 = RSAUtil.getKeyStore("H://p12/client.p12", "test12");
			String key_aliases = null;
			Enumeration<String> enumeration = keyStore2.aliases();
			key_aliases = enumeration.nextElement();
			RSAPrivateKey privateKey = (RSAPrivateKey) keyStore2.getKey(key_aliases, keyPassword.toCharArray());
			CertificateFactory certificatefactory=CertificateFactory.getInstance(CERT_TYPE_X509);
			 X509Certificate certificate = (X509Certificate)certificatefactory.generateCertificate(new FileInputStream("H://p12/client.cer"));
			 String signData = RSAUtil.signData("123456".getBytes(), null,privateKey);
			 System.out.println(signData);
			   System.out.println(RSAUtil.vefySign("123456", signData, certificate));*/
		
		
	}
	
}
